package com.net.io.netty.future;

import io.netty.channel.DefaultEventLoop;
import io.netty.util.concurrent.DefaultPromise;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutionException;

/**
 * @author zhangtengfei
 * @date 2022/2/11 17:33
 */
@Slf4j
public class FutureAndPromise {

    public static void main(String[] args) {
        FutureAndPromise futureAndPromise = new FutureAndPromise();

        try {
            // 同步处理任务成功
            futureAndPromise.sync();
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            // 同步处理任务失败 - sync & get
            futureAndPromise.syncError();
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            // 同步处理任务失败 - await
            futureAndPromise.syncErrorAwait();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 异步处理任务成功
        futureAndPromise.asynchronous();
        // 异步处理任务失败
        futureAndPromise.asynchronousError();
        // await 死锁检查
        futureAndPromise.awaitDeadLock();
    }

    /**
     * 同步处理任务成功
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public void sync() throws ExecutionException, InterruptedException {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("set success, {}", 10);
            // 设置成功结果
            promise.setSuccess(10);
        });

        log.debug("sync start...");
        // 获取任务结果，非阻塞，还未产生结果时返回 null
        log.debug("getNow: {}", promise.getNow());
        // 获取任务结果，阻塞等待。如果任务失败，抛出异常
        log.debug("get: {}", promise.get());
    }

    /**
     * 同步处理任务失败 - sync & get
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public void syncError() throws ExecutionException, InterruptedException {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            RuntimeException e = new RuntimeException("error...");
            log.debug("set failure, {}", e.toString());
            // 设置失败结果
            promise.setFailure(e);
        });

        log.debug("syncError start...");
        // 获取任务结果，非阻塞，还未产生结果时返回 null
        log.debug("{}", promise.getNow());
        // 获取任务结果，阻塞等待。如果任务失败，抛出异常.只是 get 会再用 ExecutionException 包一层异常
        log.debug("{}", promise.get());

    }

    /**
     * 同步处理任务失败 - await
     *
     * @throws InterruptedException
     */
    public void syncErrorAwait() throws InterruptedException {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            RuntimeException e = new RuntimeException("error...");
            log.debug("set failure, {}", e.toString());
            promise.setFailure(e);
        });

        log.debug("syncErrorAwait start...");
        log.debug("getNow: {}", promise.getNow());
        // 等待任务结束，如果任务失败，不会抛异常，而是通过 isSuccess 判断
        promise.await(); // 与 sync 和 get 区别在于，不会抛异常
        log.debug("result: {}", (promise.isSuccess() ? promise.getNow() : promise.cause()).toString());
    }

    /**
     * 异步处理任务成功
     */
    public void asynchronous() {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        // 设置回调，异步接收结果
        promise.addListener(future -> {
            // 这里的 future 就是上面的 promise
            log.debug("asynchronous {}", future.getNow());
        });

        // 等待 1000 后设置成功结果
        eventExecutors.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("asynchronous set success, {}", 10);
            promise.setSuccess(10);
        });

        log.debug("asynchronous start...");
    }

    /**
     * 异步处理任务失败
     */
    public void asynchronousError() {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        promise.addListener(future -> {
            log.debug("asynchronousError result {}", (promise.isSuccess() ? promise.getNow() : promise.cause()).toString());
        });

        eventExecutors.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            RuntimeException e = new RuntimeException("error...");
            log.debug("asynchronousError set failure, {}", e.toString());
            promise.setFailure(e);
        });

        log.debug("asynchronousError start...");
    }

    /**
     * await 死锁检查
     */
    public void awaitDeadLock() {
        DefaultEventLoop eventExecutors = new DefaultEventLoop();
        DefaultPromise<Integer> promise = new DefaultPromise<>(eventExecutors);

        eventExecutors.submit(() -> {
            System.out.println("1");
            try {
                promise.await();
                // 注意不能仅捕获 InterruptedException 异常
                // 否则 死锁检查抛出的 BlockingOperationException 会继续向上传播
                // 而提交的任务会被包装为 PromiseTask，它的 run 方法中会 catch 所有异常然后设置为 Promise 的失败结果而不会抛出
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("2");
        });
        eventExecutors.submit(() -> {
            System.out.println("3");
            try {
                promise.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("4");
        });
    }
}
